package web.sms.mvc.service.impl;

import cn.palerock.core.shiro.useradmin.auditor.UserAuditor;
import cn.palerock.utils.StringUtils;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import web.sms.core.exception.AttributeCheckFailureException;
import web.sms.core.exception.ServiceException;
import web.sms.core.exception.shiro.ServiceExceptionCallback;
import web.sms.core.utils.MessageFormatter;
import web.sms.mvc.constant.UserConstant;
import web.sms.mvc.constant.WorkerOrderConstant;
import web.sms.mvc.dao.*;
import web.sms.mvc.entity.*;
import web.sms.mvc.entity.Process;
import web.sms.mvc.entity.pojo.WorkerCaptain;
import web.sms.mvc.entity.pojo.WorkerOrderInfo;
import web.sms.mvc.service.RemindService;
import web.sms.mvc.service.UserService;
import web.sms.mvc.service.WorkOrderService;
import web.sms.utils.ObjectUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * 时间： 2017/12/19
 *
 * @author Eoly
 */
@Service
public class WorkOrderServiceImpl implements WorkOrderService {

    private final UserService userService;
    private final TaskAssignmentMapper taskAssignmentMapper;
    private final ProcessMapper processMapper;
    private final WorkOrderMapper workOrderMapper;
    private final UserAuditor userAuditor;
    private final RemindService remindService;
    private final UserMapper userMapper;
    private final WorkerGroupMapper workerGroupMapper;
    private final Logger logger = LoggerFactory.getLogger(WorkOrderService.class);

    @Autowired
    public WorkOrderServiceImpl(UserService userService, TaskAssignmentMapper taskAssignmentMapper, ProcessMapper processMapper, WorkOrderMapper workOrderMapper, UserAuditor userAuditor, RemindService remindService, UserMapper userMapper, WorkerGroupMapper workerGroupMapper) {
        this.userService = userService;
        this.taskAssignmentMapper = taskAssignmentMapper;
        this.processMapper = processMapper;
        this.workOrderMapper = workOrderMapper;
        this.userAuditor = userAuditor;
        this.remindService = remindService;
        this.userMapper = userMapper;
        this.workerGroupMapper = workerGroupMapper;
    }

    @Override
    public Integer addWorkOrder(WorkOrder workOrder, Set<Integer> taskProcessIdSet) {
        // 检查权限
        userAuditor.checkPerms("order:admin|order:add");
        // 检查属性
        checkOrderProperties(workOrder, "orderCustomerId",
                "orderPrice");
        emptyOrderProperties(workOrder, "orderId", "orderNumber", "orderStatus",
                "orderCustomerName", "orderIsQuick", "orderCustomerMessage", "orderProductionManagerId");
        // 检查流程
        if (taskProcessIdSet.size() < 1) {
            throw new ServiceException(WorkerOrderConstant.FAIL_TO_ADD_ORDER_ERROR,
                    WorkerOrderConstant.PROCESS_NOT_SELECTED);
        }
        // 默认添加打包和发货流程
        taskProcessIdSet.add(7);
        taskProcessIdSet.add(8);
        // 检查客户
        boolean isCustomer = userService.hasRole(workOrder.getOrderCustomerId(),
                "customer|customer_special", UserConstant.CUSTOMER_NOT_EXIST_ERROR);
        if (!isCustomer) {
            throw new ServiceException(WorkerOrderConstant.FAIL_TO_ADD_ORDER_ERROR,
                    UserConstant.USER_IS_NOT_CUSTOMER);
        }
        /*检查生产管理 [功能取消]

        boolean isProductionManager = userService.hasRole(workOrder.getOrderProductionManagerId(),
                "production_manager", UserConstant.PRODUCTION_MANAGER_NOT_EXIST_ERROR);
        if (!isProductionManager) {
            throw new ServiceException(WorkerOrderConstant.FAIL_TO_ADD_ORDER_ERROR,
                    UserConstant.USER_IS_NOT_PRODUCTION_MANAGER);
        }*/
        // 检查销售管理
        boolean isSalesManager = userService.hasRole(workOrder.getOrderChargeManagerId(),
                "sales_manager", UserConstant.SALES_MANAGER_NOT_EXIST_ERROR);
        if (!isSalesManager) {
            throw new ServiceException(WorkerOrderConstant.FAIL_TO_ADD_ORDER_ERROR,
                    UserConstant.USER_IS_NOT_SALES_MANAGER);
        }
        // 检查工单金额
        if (workOrder.getOrderPrice() < 0) {
            throw new ServiceException(WorkerOrderConstant.FAIL_TO_ADD_ORDER_ERROR,
                    WorkerOrderConstant.PRICE_CAN_NOT_BE_NEGATIVE);
        }
        // 根据当前时间获取任务及工单编号
        String taskNo = Long.toString(System.currentTimeMillis(), 6);
        workOrder.setOrderTaskNo(taskNo);
        workOrder.setOrderNumber(taskNo);
        // 执行添加工单操作
        Integer result = workOrderMapper.insertSelective(workOrder);
        if (result < 1) {
            throw new ServiceException(WorkerOrderConstant.FAIL_TO_ADD_ORDER_ERROR,
                    WorkerOrderConstant.ADD_ORDER_FAILURE);
        }
        // 添加工单任务
        for (Integer processId : taskProcessIdSet) {
            addTaskAssignment(processId, taskNo);
        }

        /*
         * 提醒
         */
        // 客户提醒
        remindService.doRemind(
                new Remind(
                        workOrder.getOrderCustomerId(), MessageFormatter.arrayFormat(
                        WorkerOrderConstant.REMIND_CUSTOMER_ORDER_BIRTH,
                        new String[]{workOrder.getOrderNumber()}
                ).getMessage(), workOrder.getOrderId()
                ), Remind.ORDER_REMIND_TYPE
        );
        // 销售管理提醒
        remindService.doRemind(
                new Remind(
                        workOrder.getOrderChargeManagerId(), MessageFormatter.arrayFormat(
                        WorkerOrderConstant.REMIND_MANAGER_ORDER_BIRTH,
                        new String[]{workOrder.getOrderNumber()}
                ).getMessage(), workOrder.getOrderId()
                ), Remind.ORDER_REMIND_TYPE
        );
        return workOrder.getOrderId();
    }

    @Override
    public PageInfo<WorkOrder> findWorkOrderByPage(WorkOrder checkOrder, Integer pageNum, Integer pageSize) {
        // 获取当前登录用户，并检查
        User userLogged = (User) userAuditor.getSession().getAttribute("userLogged");
        UserServiceImpl.checkUserProperties(userLogged, "userRole");
        if ("admin".equals(userLogged.getUserRole()) ||
                "clerk".equals(userLogged.getUserRole()) ||
                "production_manager".equals(userLogged.getUserRole())) {
            // 若当前登录用户是管理员或文员,获取所有订单信息
            return this.findAllOrders(checkOrder, pageNum, pageSize);
        }
        if ("customer".equals(userLogged.getUserRole()) ||
                "customer_special".equals(userLogged.getUserRole())) {
            // 获取客户对应的订单信息
            return this.findCustomerOrders(pageNum, pageSize, userLogged.getUserId());
        }
        if ("sales_manager".equals(userLogged.getUserRole())) {
            // 获取销售管理的订单信息
            return this.findSManagerOrders(pageNum, pageSize, userLogged.getUserId());
        }
        throw new ServiceException(WorkerOrderConstant.NO_ORDERS_DISPLAYED);
    }

    @Override
    public List<WorkOrder> findSManageOrders(Integer sManagerId, Date startTime, Date endTime) {
        if (sManagerId == null) {
            sManagerId = (Integer) userAuditor.getCurrentSubjectUniqueKey(
                    new ServiceExceptionCallback());
        }
        userAuditor.checkPerms("order:admin|order:find", sManagerId);
        return workOrderMapper.selectOrderBySManagerId(null, null,
                sManagerId, startTime, endTime, true);
    }

    @Override
    public void deleteWorkOrder(Integer orderId) {
        // 检查权限
        userAuditor.checkPerms("order:admin|order:delete");
        WorkOrder order = workOrderMapper.selectByPrimaryKey(orderId);
        if (order == null) {
            throw new ServiceException(WorkerOrderConstant.ORDER_NOT_EXIST_ERROR);
        }
        // 执行删除操作
        WorkOrder editOrder = new WorkOrder();
        editOrder.setOrderId(order.getOrderId());
        editOrder.setOrderStatus(WorkOrder.NOT_EXIST_STATUS);
        this.editWorkOrderWithoutCheck(editOrder, WorkerOrderConstant.DELETE_ORDER_FAILURE);

        /*
         * 提醒
         */
        // 客户提醒
        remindService.doRemind(
                new Remind(
                        order.getOrderCustomerId(), MessageFormatter.arrayFormat(
                        WorkerOrderConstant.REMIND_CUSTOMER_ORDER_DELETE,
                        new String[]{order.getOrderNumber()}
                ).getMessage()
                ), Remind.NORMAL_TYPE
        );
        // 销售管理提醒
        remindService.doRemind(
                new Remind(
                        order.getOrderChargeManagerId(), MessageFormatter.arrayFormat(
                        WorkerOrderConstant.REMIND_MANAGER_ORDER_DELETE,
                        new String[]{order.getOrderNumber()}
                ).getMessage()
                ), Remind.NORMAL_TYPE
        );
    }

    @Override
    public void editWorkOrderLeftMessage(Integer orderId, String message) {
        if (orderId == null) {
            throw new ServiceException(WorkerOrderConstant.THERE_IS_NO_ORDER_ID);
        }
        if (message == null || "".equals(message)) {
            throw new ServiceException(WorkerOrderConstant.CUSTOMER_MESSAGE_IS_EMPTY_ERROR);
        }
        WorkOrder order = workOrderMapper.selectByPrimaryKey(orderId);
        if (order == null) {
            throw new ServiceException(WorkerOrderConstant.ORDER_NOT_EXIST_ERROR);
        }
        Integer customerId = (Integer) userAuditor.
                getCurrentSubjectUniqueKey(new ServiceExceptionCallback());
        // 判断当前用户是不是该工单对应的客户
        if (customerId == null || !customerId.equals(order.getOrderCustomerId())) {
            throw new ServiceException(
                    WorkerOrderConstant.CURRENT_USER_IS_NOT_RIGHT_CUSTOMER_ERROR);
        }
        // 执行工单留言修改操作
        WorkOrder editOrder = new WorkOrder();
        editOrder.setOrderId(order.getOrderId());
        editOrder.setOrderCustomerMessage(message);
        this.editWorkOrderWithoutCheck(editOrder,
                WorkerOrderConstant.EDIT_CUSTOMER_MESSAGE_FAILURE);
        // 获取所有生产管理
        User userModel = new User();
        userModel.setUserStatus(User.NORMAL_USER_STATUS);
        userModel.setUserRole("production_manager");
        List<User> pmanages = userMapper.selectAllUserByAttributes(userModel, null);
        if (pmanages != null && pmanages.size() != 0) {
            for (User pamanage : pmanages) {
                remindService.doRemind(
                        new Remind(
                                pamanage.getUserId(), MessageFormatter.arrayFormat(
                                WorkerOrderConstant.REMIND_ORDER_MESSAGE_CHANGED,
                                new String[]{order.getOrderTaskNo()}
                        ).getMessage(), orderId
                        ), Remind.ORDER_REMIND_TYPE
                );
            }
        }
    }

    @Override
    public void makeOrderPaid(Integer orderId) {
        // 检查权限
        userAuditor.checkPerms("order:admin|clerk:admin");
        if (orderId == null) {
            throw new ServiceException(WorkerOrderConstant.THERE_IS_NO_ORDER_ID);
        }
        WorkOrder order = workOrderMapper.selectByPrimaryKey(orderId);
        if (order == null) {
            throw new ServiceException(WorkerOrderConstant.ORDER_NOT_EXIST_ERROR);
        }
        // 判断工单支付状态
        if (WorkOrder.NOT_PAID_STATUS < order.getOrderPaymentStatus()) {
            throw new ServiceException(WorkerOrderConstant.CHANGE_ORDER_PAYMENT_STATUS_ERROR,
                    WorkerOrderConstant.ORDER_IS_PAID);
        }
        // 修改工单支付状态
        WorkOrder editOrder = new WorkOrder();
        editOrder.setOrderId(order.getOrderId());
        editOrder.setOrderPaymentStatus(WorkOrder.PAID_STATUS);
        this.editWorkOrderWithoutCheck(editOrder,
                WorkerOrderConstant.CHANGE_ORDER_PAYMENT_STATUS_FAILURE);
    }

    @Override
    public void changeOrderPriority(Integer orderId, Integer priority) {
        // 检查权限
        userAuditor.checkPerms("order:admin|smanager:admin");
        if (orderId == null) {
            throw new ServiceException(WorkerOrderConstant.THERE_IS_NO_ORDER_ID);
        }
        if (priority == null) {
            throw new ServiceException(WorkerOrderConstant.THERE_IS_NO_ORDER_PRIORITY);
        }
        WorkOrder editOrder = new WorkOrder();
        editOrder.setOrderId(orderId);
        editOrder.setOrderPriority(priority);
        editWorkOrderWithoutCheck(editOrder, WorkerOrderConstant.CHANGE_ORDER_PRIORITY_FAILURE);
    }

    @Override
    public void changeOrderIsQuick(Integer orderId, Integer isQuick) {
        // 检查权限
        userAuditor.checkPerms("order:admin|pmanager:admin");
        if (orderId == null) {
            throw new ServiceException(WorkerOrderConstant.THERE_IS_NO_ORDER_ID);
        }
        if (isQuick == null) {
            throw new ServiceException(WorkerOrderConstant.THERE_IS_NO_ORDER_IS_QUICK);
        }
        WorkOrder editOrder = new WorkOrder();
        editOrder.setOrderId(orderId);
        editOrder.setOrderIsQuick(isQuick);
        editWorkOrderWithoutCheck(editOrder, WorkerOrderConstant.CHANGE_ORDER_IS_QUICK_FAILURE);
    }

    @Override
    public WorkOrder findOrderDetail(Integer orderId) {
        WorkOrder workOrder = workOrderMapper.selectByPrimaryKey(orderId);
        ObjectUtils.checkObjectProperties(workOrder, WorkerOrderConstant.ORDER_NOT_EXIST_ERROR);
        return workOrder;
    }

    @Override
    public WorkerOrderInfo findOrderInfoWithWorkerInCycle(Integer workerId, Date startTime,
                                                          Date endTime) {
        if (workerId == null) {
            throw new ServiceException(WorkerOrderConstant.GET_ORDER_INFO_ERROR,
                    WorkerOrderConstant.WORKER_IS_NOT_EXIST);
        }
        // 检查权限
        userAuditor.checkPerms("user:admin|user:find", workerId);
        WorkerOrderInfo workerOrderInfo = workOrderMapper.selectWorkerOrderInfoByWorkerId(
                workerId, startTime, endTime
        );
        if (workerOrderInfo == null) {
            throw new ServiceException(WorkerOrderConstant.GET_ORDER_INFO_ERROR,
                    WorkerOrderConstant.NOT_EXIST_IN_THIS_TIME);
        }
        return workerOrderInfo;
    }

    @Override
    public Double getSumOfOrderPriceInCycle(Date startTime, Date endTime) {
        userAuditor.checkPerms("order:admin|order:find");
        Double result = workOrderMapper.selectAllPrice(startTime, endTime);
        if (result == null) {
            result = 0d;
        }
        return result;
    }

    /**
     * 私有方法
     * 分页查询销售管理对应所有订单信息
     *
     * @param pageNum    页码
     * @param pageSize   每页所含的订单数
     * @param sManagerId 销售管理id
     * @return 订单实体
     */
    private PageInfo<WorkOrder> findSManagerOrders(Integer pageNum,
                                                   Integer pageSize, Integer sManagerId) {
        List<WorkOrder> workOrders = workOrderMapper.selectOrderBySManagerId(
                (pageNum - 1) * pageSize, pageSize, sManagerId, null, null, false);
        if (workOrders == null || workOrders.size() < 1) {
            throw new ServiceException(WorkerOrderConstant.EMPTY_ORDER_LIST_EXCEPTION);
        }
        PageInfo<WorkOrder> pageInfo = new PageInfo<WorkOrder>(workOrders);
        pageInfo.setTotal(workOrderMapper.selectOrderCountBySManagerId(sManagerId));
        return pageInfo;
    }

    /**
     * 私有方法
     * 分页查询生产管理对应所有订单信息
     *
     * @param pageNum    页码
     * @param pageSize   每页所含的订单数
     * @param pManagerId 生产管理id
     * @return 订单实体
     */
    private PageInfo<WorkOrder> findPManagerOrders(Integer pageNum,
                                                   Integer pageSize, Integer pManagerId) {
        List<WorkOrder> workOrders = workOrderMapper.selectOrderByPManagerId(
                (pageNum - 1) * pageSize, pageSize, pManagerId);
        if (workOrders == null || workOrders.size() < 1) {
            throw new ServiceException(WorkerOrderConstant.EMPTY_ORDER_LIST_EXCEPTION);
        }
        PageInfo<WorkOrder> pageInfo = new PageInfo<WorkOrder>(workOrders);
        pageInfo.setTotal(workOrderMapper.selectOrderCountByPManagerId(pManagerId));
        return pageInfo;
    }

    /**
     * 私有方法
     * 分页查询客户对应所有订单信息
     *
     * @param pageNum  页码
     * @param pageSize 每页所含的订单数
     * @return 订单实体
     */
    private PageInfo<WorkOrder> findCustomerOrders(Integer pageNum,
                                                   Integer pageSize, Integer customerId) {
        List<WorkOrder> workOrders = workOrderMapper.selectOrderByCustomerId(
                (pageNum - 1) * pageSize, pageSize, customerId);
        if (workOrders == null || workOrders.size() < 1) {
            throw new ServiceException(WorkerOrderConstant.EMPTY_ORDER_LIST_EXCEPTION);
        }
        PageInfo<WorkOrder> pageInfo = new PageInfo<WorkOrder>(workOrders);
        pageInfo.setTotal(workOrderMapper.selectOrderCountByCustomerId(customerId));
        return pageInfo;
    }

    /**
     * 私有方法
     * 分页查询所有订单信息[可按条件]
     *
     * @param checkOrder 指定查询条件
     * @param pageNum    页码
     * @param pageSize   每页所含的订单数
     * @return 订单实体
     */
    private PageInfo<WorkOrder> findAllOrders(WorkOrder checkOrder, Integer pageNum, Integer pageSize) {
        List<WorkOrder> workOrders = workOrderMapper.selectOrdersByAttribute(checkOrder,
                (pageNum - 1) * pageSize, pageSize);
        logger.warn(JSON.toJSONString(workOrders));
        if (workOrders == null || workOrders.size() < 1) {
            throw new ServiceException(WorkerOrderConstant.EMPTY_ORDER_LIST_EXCEPTION);
        }
        PageInfo<WorkOrder> pageInfo = new PageInfo<WorkOrder>(workOrders);
        logger.warn(JSON.toJSONString(pageInfo));
        pageInfo.setTotal(workOrderMapper.selectOrdersCountByAttribute(checkOrder));
        return pageInfo;
    }

    /**
     * 检查用户及用户属性是否为空
     *
     * @param order      用户实体
     * @param properties 用户属性集合
     */
    public static void checkOrderProperties(WorkOrder order, String... properties) {
        if (order == null) {
            throw new AttributeCheckFailureException(WorkerOrderConstant.ORDER_NOT_EXIST_ERROR, "null");
        }
        for (String attributeName : properties) {
            String methodName = "get" + StringUtils.captureName(attributeName);
            try {
                Object obj = WorkOrder.class.getMethod(methodName).invoke(order);
                if (obj == null) {
                    throw new AttributeCheckFailureException(
                            WorkerOrderConstant.NULL_ORDER_PROPERTY_ERROR, attributeName,
                            new String[]{attributeName});
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 令指定用户属性值设置为空
     *
     * @param order      用户实体
     * @param properties 用户属性集
     */
    public static void emptyOrderProperties(WorkOrder order, String... properties) {
        if (order == null) {
            throw new AttributeCheckFailureException(WorkerOrderConstant.ORDER_NOT_EXIST_ERROR, "null");
        }
        for (String attributeName : properties) {
            String methodName = "set" + StringUtils.captureName(attributeName);
            Method[] methods = WorkOrder.class.getMethods();
            for (Method method : methods) {
                if (methodName.equals(method.getName())) {
                    try {
                        method.invoke(order, (Object) null);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 添加一个工单任务
     *
     * @param processId 任务对应的流程id[同一个任务编号对应的流程id不能重复]
     * @param taskNo    任务编号
     */
    private void addTaskAssignment(Integer processId, String taskNo) {
        Process process = processMapper.selectByPrimaryKey(processId);
        if (process == null) {
            throw new ServiceException(WorkerOrderConstant.FAIL_TO_ADD_ORDER_ERROR,
                    WorkerOrderConstant.PROCESS_NOT_EXIST);
        }
        // 获取相应工人组并自动分配
        List<WorkerCaptain> workerCaptains = workerGroupMapper.selectAllGroupCaptainsByProcessId(processId);
        TaskAssignment assignment = new TaskAssignment();
        assignment.setTaskProcessId(processId);
        assignment.setTaskNo(taskNo);
        if (!workerCaptains.isEmpty()) {
            assignment.setTaskWorkerGroupId(workerCaptains.get(0).getGroupId());
        }
        int result = taskAssignmentMapper.insertSelective(assignment);
        if (result < 1) {
            throw new ServiceException(WorkerOrderConstant.SERVER_RUN_SQL_FAILURE,
                    WorkerOrderConstant.ADD_ORDER_FAILURE);
        }
    }

    /**
     * 私有方法更新工单[不进行合法性检查]
     *
     * @param order          工单实体
     * @param doErrorMessage 当修改失败时的提示信息
     */
    private void editWorkOrderWithoutCheck(WorkOrder order, String doErrorMessage) {
        if (doErrorMessage == null || "".equals(doErrorMessage)) {
            doErrorMessage = WorkerOrderConstant.EDIT_ORDER_FAILURE;
        }
        int result = workOrderMapper.updateByPrimaryKeySelective(order);
        if (result < 1) {
            throw new ServiceException(WorkerOrderConstant.SERVER_RUN_SQL_FAILURE,
                    doErrorMessage);
        }
    }

    /**
     * 私有方法更新工单[不进行合法性检查]
     *
     * @param order 工单实体
     */
    private void editWorkOrderWithoutCheck(WorkOrder order) {
        this.editWorkOrderWithoutCheck(order, null);
    }
}
